#include "Board.h"

#include <cstdio>
#include <cassert>

Board::Board():ball(w/2,h/2){
	memset(items , 0, getItemsSize());
}

Board::Board(const Board& b):ball(b.ball){
	memcpy(items, b.items, getItemsSize());
	ball = b.ball;
}

Board& Board::operator=(const Board& b){
	memcpy(items, b.items, getItemsSize());
	ball = b.ball;
	return (*this);
}

Board::case_e Board::getCase(position_t p) const {
	if(!onBoard(p)){
		return CASE_OUT_OF_RANGE;
	}
	return items[p.x][p.y];
}

bool Board::isPawnPlacable(position_t p) const {
	return getCase(p)==CASE_EMPTY && p != ball;
}

bool Board::isBallPlacable(position_t p) const {
	return getCase(p)==CASE_EMPTY || onGoalZone(p);
}

bool Board::setCase(position_t p, case_e val){
	assert(val==CASE_EMPTY || val==CASE_PAWN);
	if(!onBoard(p)){
		return false;
	}
	if(p==ball){
		return false;
	}
	items[p.x][p.y] = val;
	return true;
}

position_t Board::getBallPosition() const {
	return ball;
}

bool Board::setBallPosition(position_t p){
	if(!isBallPlacable(p)){
		return false;
	}
	ball = p;
	return true;
}

bool Board::onBoard(position_t p){
	return !(p.x<0 || p.x>=Board::w || p.y<0 || p.y>=Board::h);
}

bool Board::onGoalZone(position_t p){
	return p.x<=0 ||p.x>=Board::w-1;
}

int Board::getItemsSize(){
	return Board::w*Board::h*sizeof(case_e);
}


int Board::_runTests(){
	Board b1;
	position_t ballPos(-1,0);
	b1.setBallPosition(ballPos);
	if(!(b1.getBallPosition()==ballPos)){
		printf("Ball position setting failed(%d,%d) instead of (%d,%d).\n",
			b1.getBallPosition().x,
			b1.getBallPosition().y,
			ballPos.x,
			ballPos.y);
		return 7;
	}
	for(int i = 0; i<Board::w;++i){
		for(int j = 0; j<Board::h;++j){
			if(!b1.onBoard(position_t(i,j))){
				printf("Board : Test failed for case(%d,%d)",i,j);
				return 1;
			}
		}
	}
	for(int i = 0; i<Board::w;++i){
		for(int j = 0; j<Board::h;++j){
			if(b1.getCase(position_t(i,j))!=CASE_EMPTY){
				printf("Board : Test failed for case(%d,%d)",i,j);
				return 2;
			}
		}
	}
	for(int i = 0; i<Board::w;++i){
		for(int j = 0; j<Board::h;++j){
			b1.setCase(position_t(i,j),CASE_PAWN);
			if(b1.getCase(position_t(i,j))!=CASE_PAWN){
				printf("Board : Test failed for case(%d,%d)",i,j);
				return 4;
			}
		}
	}
	if(b1.getCase(position_t(-1, 0))!=CASE_OUT_OF_RANGE) return 3;
	if(b1.getCase(position_t( w, 0))!=CASE_OUT_OF_RANGE) return 3;
	if(b1.getCase(position_t( 0,-1))!=CASE_OUT_OF_RANGE) return 3;
	if(b1.getCase(position_t( 0, h))!=CASE_OUT_OF_RANGE) return 3;
	Board b2(b1);
	for(int i = 0; i<Board::w;++i){
		for(int j = 0; j<Board::h;++j){
			if(b2.getCase(position_t(i,j))!=CASE_PAWN){
				printf("Board : Test failed for case(%d,%d)",i,j);
				return 5;
			}
		}
	}
	Board b3;
	b3 = b1;
	for(int i = 0; i<Board::w;++i){
		for(int j = 0; j<Board::h;++j){
			if(b3.getCase(position_t(i,j))!=CASE_PAWN){
				printf("Board : Test failed for case(%d,%d)",i,j);
				return 6;
			}
		}
	}
	printf("Board test succeded.\n");
	return 0;
}